#ifndef TCP_SERVER_HPP
#define TCP_SERVER_HPP

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <string>
#include <thread>
#include "thread_pool/logmessage.hpp"
#include "thread_pool/threadpool.hpp"
#include "thread_pool/task.hpp"

class TcpServer
{
    typedef zty::thread_pool<zty::Task> thread_pool;
    uint16_t _port;
    int _listensock;
    thread_pool &_tp;
    const static int s_backlog = 5;

public:
    TcpServer(const uint16_t port)
        : _port(port),
          _listensock(-1),
          _tp(thread_pool::GetInstance(5))
    {
        _tp.run();
    }

    void InitServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1)
        {
            LogMessage(FATAL, "socket error: %s (%d)", strerror(errno), errno);
            exit(errno);
        }
        LogMessage(DEBUG, "create socket success: %d", _listensock);

        sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) == -1)
        {
            LogMessage(FATAL, "bind error: %s (%d)", strerror(errno), errno);
            exit(errno);
        }
        LogMessage(DEBUG, "bind socket success");

        if (listen(_listensock, s_backlog) == -1)
        {
            LogMessage(FATAL, "listen error: %s (%d)", strerror(errno), errno);
            exit(errno);
        }
        LogMessage(DEBUG, "listen socket success");
    }

    void Start()
    {
        // signal(SIGCHLD, SIG_IGN);
        for (;;)
        {
            sockaddr_in client;
            memset(&client, 0, sizeof(client));
            socklen_t len = sizeof(client);
            int servicesock = accept(_listensock, (sockaddr *)&client, &len);
            if (servicesock == -1)
            {
                LogMessage(ERROR, "accept error: %s (%d)", strerror(errno), errno);
                continue;
            }
            LogMessage(NORMAL, "accept client success: %d", servicesock);

            // 1.单执行流版
            // Service(servicesock, client);

            // 2.多进程版 —— 忽略SIGCHLD信号
            // if (fork() == 0)
            // {
            //     // 子进程执行流
            //     close(_listensock); // 子进程不需要监听套接字
            //     Service(servicesock, client);
            //     exit(0);
            // }
            // // 父进程需要关闭服务套接字，防止文件描述符泄漏
            // close(servicesock);

            // 3.多进程版 —— 创建孙进程提供服务
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // 子进程执行流
            //     close(_listensock); // 子进程不需要监听套接字
            //     if (fork() == 0)
            //     {
            //         // 孙进程执行流
            //         Service(servicesock, client);
            //         exit(0); // 孙进程退出后由1号进程负责回收工作
            //     }
            //     exit(0); //子进程创建孙进程后立即退出
            // }
            // waitpid(id, nullptr, 0);
            // close(servicesock);

            // 4.多线程版
            // std::thread t1(Service, servicesock, client);
            // t1.detach(); // 线程分离，不需要主线程join

            // 5.线程池版
            zty::Task task(Service, servicesock, client);
            // zty::Task task(Change, servicesock, client);
            _tp.push(task);
        }
    }

    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
    }

private:
    // 通信服务
    static void Service(int sockfd, sockaddr_in client)
    {
        char buffer[1024];
        std::string client_ip = inet_ntoa(client.sin_addr);
        uint16_t client_port = ntohs(client.sin_port);
        for (;;)
        {
            ssize_t s = read(sockfd, buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] = 0;
                printf("[%s:%d]# %s\n", client_ip.c_str(), client_port, buffer);
                write(sockfd, buffer, strlen(buffer));
            }
            else if (s == 0)
            {
                LogMessage(NORMAL, "client quit, disconnected [%s:%d]", client_ip.c_str(), client_port);

                break;
            }
        }
        // 通信服务结束后，一定要关闭服务套接字，防止套接字泄漏
        close(sockfd);
    }

    // 大小写转换服务 （简单，短暂，适用于线程池）
    static void Change(int sockfd, sockaddr_in client)
    {
        char buffer[1024];
        std::string client_ip = inet_ntoa(client.sin_addr);
        uint16_t client_port = ntohs(client.sin_port);
        for (;;)
        {
            ssize_t s = read(sockfd, buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] = 0;
                printf("[%s:%d]# %s\n", client_ip.c_str(), client_port, buffer);
                for (int i = 0; i < strlen(buffer); ++i)
                {
                    buffer[i] &= ~32;
                }
                std::string echo = buffer;
                echo += " (thread-";
                echo += std::to_string(pthread_self() % 10000);
                echo += ")";
                write(sockfd, echo.c_str(), echo.size());
            }
            else if (s == 0)
            {
                LogMessage(NORMAL, "client quit, disconnected [%s:%d]", client_ip.c_str(), client_port);
                break;
            }
        }
        // 通信服务结束后，一定要关闭服务套接字，防止套接字泄漏
        close(sockfd);
    }
};

#endif